/*****************************************************************************
* File Name: Application.c
*
* Version: 1.0
*
* Description:
* This module handles state machine for HID Host operation.
*
* Note:
* None
*
* Owner: SIRK
*
* Related Document:
* HOGP Spec V1.0
* BLE Component datasheet
*
* Hardware Dependency:
* CY5670 CySmart USB Dongle
*
* Code Tested With:
* 1. PSoC Creator 3.1 
* 2. ARM GCC 4.8.4
******************************************************************************
* Copyright (2015), Cypress Semiconductor Corporation.
******************************************************************************
* This software is owned by Cypress Semiconductor Corporation (Cypress) and is
* protected by and subject to worldwide patent protection (United States and
* foreign), United States copyright laws and international treaty provisions.
* Cypress hereby grants to licensee a personal, non-exclusive, non-transferable
* license to copy, use, modify, create derivative works of, and compile the
* Cypress Source Code and derivative works for the sole purpose of creating
* custom software in support of licensee product to be used only in conjunction
* with a Cypress integrated circuit as specified in the applicable agreement.
* Any reproduction, modification, translation, compilation, or representation of
* this software except as specified above is prohibited without the express
* written permission of Cypress.
*
* Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 
* Cypress reserves the right to make changes without further notice to the
* materials described herein. Cypress does not assume any liability arising out
* of the application or use of any product or circuit described herein. Cypress
* does not authorize its products for use as critical components in life-support
* systems where a malfunction or failure may reasonably be expected to result in
* significant injury to the user. The inclusion of Cypress' product in a life-
* support systems application implies that the manufacturer assumes all risk of
* such use and in doing so indemnifies Cypress against all charges. Use may be
* limited by and subject to the applicable Cypress software license agreement.
*****************************************************************************/

#include "Application.h"
#include ".\CySmt_InterfaceModule\CySmt_protocol.h"

/* Macros for expected HID Report IDs */
/*Below IDs are used by USB HID Descriptor of PSoC5-LP*/
#define MOUSE_REPORT_ID                                 (1u)
#define KEYBOARD_REPORT_ID                              (2u)
#define MULTIMEDIA_REPORT_ID                            (3u)
#define POWER_REPORT_ID                                 (4u)
#define GAMEPAD_REPORT_ID                               (5u)
#define BATTERY_FEATURE_REPORT_ID                       (6u)

#define MOUSE_REPORT_SIZE                               (6u)
#define POWER_REPORT_SIZE                               (2u)
#define MULTIMEDIA_REPORT_SIZE                          (3u)
#define BATTERY_FEATURE_REPORT_SIZE                     (1u)

/*Macros for audio feature*/
/*For CY5682 Mouse project, Audio feature is not active, so below define should be disabled*/
#define AUDIO_OVER_HID
#define EN_WAIT_FOR_SCAN_RSP

#ifdef AUDIO_OVER_HID
#define AUDIO_CONTROL_ID                                (0xFFu)
#define AUDIO_SYNC_ID                                   (0xFEu)
#define AUDIO_ID_INDEX                                  (0x00u)
#define AUDIO_VAL_INDEX                                 (0x01u)

#define AUDIO_REPORT_ID                                 (30u)
#define AUDIO_SIGNAL_REPORT_ID                          (31u)
#endif /*AUDIO_OVER_HID*/

#ifdef AUDIO_OVER_HID

/*Enable sending auto control stop if no data */
#define EN_AUDIO_CONTROL_TIMEOUT

#ifdef EN_AUDIO_CONTROL_TIMEOUT
/*Timeout for audio control packet loss 
    if no audio data packet occurs when audio data path is on close the data path on timeout*/
#define AUDIO_CONTROL_TIMEOUT                           (3000u)

/*Timestamp of last recieved audio data packet*/
static uint32 audioCntrlTimeStamp = 0;
#endif /*EN_AUDIO_CONTROL_TIMEOUT*/

/*Status of audio data path: open/close*/
static bool audioControlOn = false;
#endif

/*Index into HID Info value for flags field.*/
#define HID_INFO_FLAGS_BYTE_INDEX                       (0x03u)
/*Indexes into HID RRD fields*/
#define HID_RRD_RID_BYTE_INDEX                          (0x00u)
#define HID_RRD_RTYPE_BYTE_INDEX                        (0x01u)

/*Disabling pathloss alert by default, to provide the best performance*/
/*This feature sends the alerts on low signal strength which depends on the hardware and antenna*/
#ifdef ENABLE_PATH_LOSS_ALERT
/*Threshold for path loss alert - this need to be signed value*/
#define RSSI_THRESHOLD_VALUE                            ((int8)78)
/*Total number of samples to be averaged*/
#define NUMBER_OF_SAMPLES_TO_AVG                        (30)
#endif //ENABLE_PATH_LOSS_ALERT

/* Dongle state machine for HID Host client  */
typedef enum
{
    /*Default state until peripheral device is discovered*/
    DONGLE_BLE_STATE_NOT_READY = 0,

    /*BLE module is configuring the server*/
    DONGLE_BLE_STATE_CONFIG,

    /*BLE is ready for any commands with peripheral*/
    DONGLE_BLE_STATE_ACTIVE,

    /*BLE module is processing current command*/
    DONGLE_BLE_STATE_BUSY
}DONGLE_BLE_STATES_T;

/* Types of reports supported by dongle bridge*/
typedef enum
{
    /*Mouse report packet with ID*/
    MOUSE_IN_REPORT,

    /*Keyboard report packet with-out ID*/
    KEYBOARD_IN_REPORT,

    /*Multimedia report packet with ID*/
    MULTIMEDIA_IN_REPORT,

    /*Power report packet with ID*/
    POWER_IN_REPORT,
  
    /*Gamepad report packet with ID*/
    GAMEPAD_IN_REPORT,
#ifdef AUDIO_OVER_HID
    /*Audio report packet with-out ID*/
    AUDIO_IN_REPORT,

    /*Audio signal packet with-out ID*/
    AUDIO_SIGNAL_REPORT,
#endif /*AUDIO_OVER_HID*/

    /*Power report packet with ID*/
    MAX_NUMBER_OF_REPORT_TYPES
}REPORT_ID_T;

/*enum for all the profile level configurations to be done on pairing and for each re-connection;
  for pre-bonded devices only encryption and MTU exchange will be done on each connection, other steps will be skipped
  Below list will be executed in decrmental order and once all the configurations are completed, system will move to active state
  New configurations need to evaluated and placed in the right order while adding into this list*/
typedef enum
{
    /*Profile level config is completed and device can move to active state*/
    BLE_CONFIG_COMPLETED = 0x00u,

#ifdef AUDIO_OVER_HID
    /*Enable notifications of Audio data report over HID if available*/
    BLE_CONFIG_HIDS_AUDIO_RPT_EN_NOTIF,
    /*Enable notifications of Audio signal report over HID if available*/
    BLE_CONFIG_HIDS_AUDIO_SIGNAL_RPT_EN_NOTIF,
#endif /*AUDIO_OVER_HID*/
    /*Enable notifications of Gamepad report if available*/
    BLE_CONFIG_HIDS_GAMEPAD_RPT_EN_NOTIF,
    /*Enable notifications of Power report if available*/
    BLE_CONFIG_HIDS_PWR_RPT_EN_NOTIF,
    /*Enable notifications of Multimedia report if available*/
    BLE_CONFIG_HIDS_MULTI_RPT_EN_NOTIF,
    /*Enable notifications of Keyboard IN report if available*/
    BLE_CONFIG_HIDS_KB_RPT_EN_NOTIF,
    /*Enable notifications of Mouse report if available*/
    BLE_CONFIG_HIDS_MOUSE_RPT_EN_NOTIF,

    /*Enable notifications of Battery service if available*/
    BLE_CONFIG_EN_BAT_LVL_NOTIF,
    /*Enable notifications of SCP service if available*/
    BLE_CONFIG_EN_SCAN_REFRESH_NOTIF,

    /*Set the link-loss alert level to be used by Device*/
    BLE_CONFIG_SET_LL_ALERT_LVL,
    /*Read RRD of report to check the report ID*/
    BLE_CONFIG_HIDS_GET_RPT6_INDEX,
    /*Read RRD of report to check the report ID*/
    BLE_CONFIG_HIDS_GET_RPT5_INDEX,
    /*Read RRD of report to check the report ID*/
    BLE_CONFIG_HIDS_GET_RPT4_INDEX,
    /*Read RRD of report to check the report ID*/
    BLE_CONFIG_HIDS_GET_RPT3_INDEX,
    /*Read RRD of report to check the report ID*/
    BLE_CONFIG_HIDS_GET_RPT2_INDEX,
    /*Read RRD of report to check the report ID*/
    BLE_CONFIG_HIDS_GET_RPT1_INDEX,
    /*Read HID Information characteristic, to find remote wake-up capability*/
    BLE_CONFIG_HIDS_GET_INFO_VAL,

#ifdef ENABLE_PATH_LOSS_ALERT
    /*Read TX power level to be used for Proximity monitoring*/
    BLE_CONFIG_GET_TX_PWR_LVL,
#endif //ENABLE_PATH_LOSS_ALERT

    /*Write the scan parameters to device as recommended by SCP spec*/
    BLE_CONFIG_SET_SCAN_INT_WIN,
    /*Write the alert level as recommended by IAS spec*/
    BLE_CONFIG_SET_IAS_NO_ALERT,
    /*Write HID protocol to Report mode, Boot mode is not used by Dongle*/
    BLE_CONFIG_SET_HIDS_PROTOCOL_MODE,
    /*Write HID protocol mode to wake-up by default*/
    BLE_CONFIG_SET_HIDS_CP,

    /*Below configurations will be executed for every re-connection of pre-bonded device*/

    /*Update the connection parameters as suggested by Device*/
    BLE_CONFIG_SET_PREF_CONN_PARAMS,
    /*Read peripheral prefered connection parameters*/
    BLE_CONFIG_GET_PREF_CONN_PARAMS,

    /*Exchange the MTU Size to max possible value*/
    BLE_EXCHANGE_MTU_SIZE,
    /*Start the encryption process*/
    BLE_BINDING_PROCESS,
    TOTAL_NUM_CONFIG_REQUESTS
}BLE_DEVICE_CONFIG_REQS_T;

/*Mapping of HID Report ID to GATT Char index*/
typedef struct _Report_Map
{
    uint8 ReportId;
    CYBLE_HIDS_CHAR_INDEX_T charIndex;
}Report_Map;

/*Initialize flag for button trigger*/
volatile static bool isButtonTriggered = false;

/*Flag for device with HID UUID*/
static bool hidDeviceFound = false;

#ifdef EN_WAIT_FOR_SCAN_RSP
/*Flag for device which is waiting for scan*/
static bool isScanRspOccured = false;
#endif /*EN_WAIT_FOR_SCAN_RSP*/

/*Skip the HID and PXP profile level configuration on re-connections*/
static bool skipProfileConfig = false;
/*Terminate the BLE Link on detecting errors and on Button press*/
static bool terminateLink = false;
/*If the HID Device doesnt supports remote wakeup, it can be disconnected on suspend*/
static bool isWakeupCapable = false;

#ifdef ENABLE_PATH_LOSS_ALERT
/*Initialize Tx Power Level and path-loss to default numbers which will be used by proximity monitor*/
static int8 Tx_Power_Level = 0; /*Default TX power level expected is 0dbm*/
static int8 rxPathLoss = RSSI_THRESHOLD_VALUE - 1;
/*Static buffer to contain the samples to be averaged, init with the default values*/
static int8 rssiSamples[NUMBER_OF_SAMPLES_TO_AVG];
#endif //ENABLE_PATH_LOSS_ALERT

/*Check if current connection is non-bonded and write scan interval as per SCP Profile*/
static uint8 isBonded = CYBLE_GAP_BONDING_NONE;

/*Number of Profile and application specific configurations*/
static BLE_DEVICE_CONFIG_REQS_T currentConfigState = TOTAL_NUM_CONFIG_REQUESTS;

/*Address of detected device*/
static CYBLE_GAP_BD_ADDR_T detectedServerAddr;

/*Record the last sent report and reset the report in case of link disconnection*/
static REPORT_ID_T lastSentReport = MAX_NUMBER_OF_REPORT_TYPES;

/*Peripheral preffered connection parameters*/
static CYBLE_GAP_CONN_UPDATE_PARAM_T prefConnParams = 
        {CYBLE_GAPC_CONNECTION_INTERVAL_MIN, CYBLE_GAPC_CONNECTION_INTERVAL_MAX,
        CYBLE_GAPC_CONNECTION_SLAVE_LATENCY, CYBLE_GAPC_CONNECTION_TIME_OUT};

/*Report ID & char index map with-in HID service for all expected report IDs*/
static Report_Map report_Map_Table[MAX_NUMBER_OF_REPORT_TYPES];

/*Initialize state machine.*/
static DONGLE_BLE_STATES_T DongleBleState = DONGLE_BLE_STATE_NOT_READY;

/*****************************************************************************
* Function Name: DongleBleAssert()
******************************************************************************
* Summary:
* This functions asserts if any unexpected errors occur in BLE API calls
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
* 
* Side Effects:
* Code flow will be halted if ENABLE_ASSERT is enabled.
* 
*****************************************************************************/
static void DongleBleAssert(void)
{
    /*Should not come here, check the failure reasons*/
    Led_Stop();
#ifdef ENABLE_ASSERT
    while(1);
#endif /*ENABLE_ASSERT*/
}

/*****************************************************************************
* Function Name: StartDeviceScanning()
******************************************************************************
* Summary:
* This function starts scanning as per device configuration.
* Uses white-list filter, if any pre-bonded info available
* Performs normal scan with-out filter, if user button is pressed
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
* 
*****************************************************************************/
static void StartDeviceScanning(void)
{
    /*Start scanning, if failed assert*/    
    if(CYBLE_STATE_DISCONNECTED == CyBle_GetState()) 
    {
        Led_Stop();
        if(CYBLE_ERROR_OK != CyBle_GapcStartScan(CYBLE_SCANNING_CUSTOM))
        {
            DongleBleAssert();
        }
    }
}

/*****************************************************************************
* Function Name: BLE_Disconnect()
******************************************************************************
* Summary:
* This function Checks the state and issues GAP Disconnect.
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
* 
* Side Effects:
* None
* 
*****************************************************************************/
static void BLE_Disconnect(void)
{
    /*Dont issue disconnect, if auth process is in progress*/
    /*Current config state will be reset when AUTH_REQ fails or times-out*/
    if(BLE_BINDING_PROCESS != currentConfigState)
    {
        if(CYBLE_ERROR_OK != CyBle_GapDisconnect(cyBle_connHandle.bdHandle))
        {
            DongleBleAssert();
        }
    }
}

#ifdef CYBLE_HIDS_CLIENT
/*****************************************************************************
* Function Name: Set_Device_ControlPoint()
******************************************************************************
* Summary:
* This function sets HID Device control point of each HID service.
*
* Parameters:
* uint8 attrib - value of the CP attribute
* uint8 hidSerIndex - Index of HID service on the server
*
* Return:
* Return value is of type CYBLE_API_RESULT_T.
* CYBLE_ERROR_OK - The request was sent successfully
* CYBLE_ERROR_INVALID_PARAMETER - Validation of the input parameters failed
* CYBLE_ERROR_MEMORY_ALLOCATION_FAILED - Memory allocation failed
* CYBLE_ERROR_GATT_DB_INVALID_ATTR_HANDLE - The peer device doesn't have
                                             the particular characteristic
* CYBLE_ERROR_INVALID_OPERATION - Operation is invalid for this
                                   characteristic
*
* Theory:
* This function will issue the write request with passed values, the operation is success only if return is CYBLE_ERROR_OK
* 
* Side Effects:
* None
* 
*****************************************************************************/
static CYBLE_API_RESULT_T Set_Device_ControlPoint(uint8 attrib,uint8 hidSerIndex)
{
    CYBLE_API_RESULT_T apiResult;
    apiResult = CyBle_HidscSetCharacteristicValue(cyBle_connHandle,
                                    CYBLE_HIDSC_WRITE_WITHOUT_RESPONSE, hidSerIndex,
                                    CYBLE_HIDS_CONTROL_POINT, sizeof(attrib), &attrib);
    if(CYBLE_ERROR_OK != apiResult)
    {
        DongleBleAssert();
    }
    else
    {
        /*Move to next configuration as no response expected for this operation*/
    }
    return apiResult;
}

/*****************************************************************************
* Function Name: EnableHidscNotif()
******************************************************************************
* Summary:
* This function enables notification for HID reports.
*
* Parameters:
* uint8 hidSerIndex - Index of HID service on the server
* CYBLE_HIDS_CHAR_INDEX_T charIndex - Index of charesteristic to which notifications to be enabled
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* Modifies DongleBleState
* 
*****************************************************************************/
static void EnableHidscNotif(uint8 hidSerIndex, CYBLE_HIDS_CHAR_INDEX_T charIndex)
{
    uint16 attrValue = CYBLE_CCCD_NOTIFICATION;
    if (CYBLE_ERROR_OK != CyBle_HidscSetCharacteristicDescriptor(
                    cyBle_connHandle,
                    hidSerIndex,
                    charIndex,
                    CYBLE_HIDS_REPORT_CCCD,
                    sizeof(attrValue),
                    (uint8 *)&attrValue ))
    {
        DongleBleAssert();
    }
    else
    {
        DongleBleState = DONGLE_BLE_STATE_BUSY;
    }
}
#endif /*CYBLE_HIDS_CLIENT*/

/*****************************************************************************
* Function Name: Set_Ias_AlertLevel()
******************************************************************************
* Summary:
* This function sets device's immediate alert level to no alert.
*
* Parameters:
* void
*
* Return:
* CYBLE_API_RESULT_T
*
* Theory:
* None
*
* Side Effects:
* None
* 
*****************************************************************************/
static CYBLE_API_RESULT_T Set_Ias_AlertLevel(uint8 attrib)
{
    CYBLE_API_RESULT_T apiResult;
    apiResult = CyBle_IascSetCharacteristicValue(cyBle_connHandle, CYBLE_IAS_ALERT_LEVEL,
                    sizeof(attrib), &attrib);
    if(CYBLE_ERROR_OK != apiResult)
    {
        DongleBleAssert();
    }
    return apiResult;
}

/*****************************************************************************
* Function Name: DongleBleConfig()
******************************************************************************
* Summary:
* This function Configures the connected device attributes to match with expected HID and proximity roles.
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
* 
*****************************************************************************/
static void DongleBleConfig(void)
{  
    static CYBLE_HIDS_CHAR_INDEX_T reportIndex;

    if(BLE_CONFIG_COMPLETED == currentConfigState)
    {
        /*Exit the state if all the configurations are complete*/
        DongleBleState = DONGLE_BLE_STATE_ACTIVE;
        return;
    }

    switch(--currentConfigState)
    {
        case BLE_BINDING_PROCESS:
            {
               /*Start bind process for each new device*/
               if(CYBLE_ERROR_OK == CyBle_GapAuthReq(cyBle_connHandle.bdHandle, &cyBle_authInfo))
               {
                   DongleBleState = DONGLE_BLE_STATE_BUSY;
               }
               else
               {
                   /*Disconnect if authentication is not complete, start scan for new devices*/
                   /*Issue disconnect on timeout*/
                   terminateLink = true;
                   /*Reset the config state, to proceed with disconnection*/
                   currentConfigState = TOTAL_NUM_CONFIG_REQUESTS;
               }
            }
            break;

        case BLE_EXCHANGE_MTU_SIZE:
            {
                /*Exchange MTU size to be higher level, if supported by peripheral*/
                if(CYBLE_ERROR_OK == CyBle_GattcExchangeMtuReq(cyBle_connHandle, CYBLE_GATT_MTU))
                {
                    DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_GET_PREF_CONN_PARAMS:
            {
               /*Read the peripheral preffered connection parameters*/
                if(CYBLE_ERROR_OK == CyBle_GattcReadCharacteristicValue(cyBle_connHandle, cyBle_gapc.prefConnParamCharHandle))
                {
                    DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_SET_PREF_CONN_PARAMS:
            {
                /*Send update request for connection parameters, no need to wait for update response*/
                (void)CyBle_GapcConnectionParamUpdateRequest(cyBle_connHandle.bdHandle, &prefConnParams);

                /*For pre-configured devices, no need of repeating configuartion on re-connections*/
                if(skipProfileConfig)
                {
                    skipProfileConfig = false;
                    currentConfigState = BLE_CONFIG_COMPLETED;
                }
            }
            break;

        case BLE_CONFIG_SET_HIDS_CP:
#ifdef CYBLE_HIDS_CLIENT
            /*Set control point to exit-suspend*/ /*No state change, as this write doesnt have response*/
            (void)Set_Device_ControlPoint(CYBLE_HIDS_CP_EXIT_SUSPEND, 0);
#endif /*CYBLE_HIDS_CLIENT*/
            break;

        case BLE_CONFIG_SET_HIDS_PROTOCOL_MODE:
            {
#ifdef CYBLE_HIDS_CLIENT
                /*Set report protocol to report mode*/ /*No state change, as this write doesnt have response*/
                uint8 attrib = CYBLE_HIDS_PROTOCOL_MODE_REPORT;
                      
                if(CYBLE_ERROR_OK != CyBle_HidscSetCharacteristicValue(cyBle_connHandle,
                                          CYBLE_HIDSC_WRITE_WITHOUT_RESPONSE, 0,
                                          CYBLE_HIDS_PROTOCOL_MODE,
                                          sizeof(attrib), &attrib))
                {
                     DongleBleAssert();
                }
            }
#endif /*CYBLE_HIDS_CLIENT*/
            break;

        case BLE_CONFIG_SET_IAS_NO_ALERT:
#ifdef CYBLE_IAS_CLIENT
            /*Set IAS to no alert by default*/
            /*No state change, as this write doesnt have response*/
            (void)Set_Ias_AlertLevel(CYBLE_NO_ALERT);
#endif /*CYBLE_IAS_CLIENT*/
            break;

        case BLE_CONFIG_SET_SCAN_INT_WIN:
#ifdef CYBLE_SCPS_CLIENT
            if(CYBLE_GAP_BONDING_NONE == isBonded)
            {
                uint8 attr[CYBLE_INTERVAL_WINDOW_CHAR_LEN];

                CyBle_Set16ByPtr(attr, CYBLE_FAST_SCAN_INTERVAL);
                CyBle_Set16ByPtr(&attr[sizeof(uint16)], CYBLE_FAST_SCAN_WINDOW);

                /*Set Scan interval window if non-bonded device is connected*/
                /*No state change, as this write doesnt have response*/
                if(CYBLE_ERROR_OK != CyBle_ScpscSetCharacteristicValue(cyBle_connHandle,
                                                CYBLE_SCPS_SCAN_INT_WIN,
                                                sizeof(attr), attr))
                {
                    DongleBleAssert();
                }
            }
#endif /*CYBLE_SCPS_CLIENT*/
            break;

#ifdef ENABLE_PATH_LOSS_ALERT
        case BLE_CONFIG_GET_TX_PWR_LVL:
#ifdef CYBLE_TPS_CLIENT
            {
                if (CYBLE_ERROR_OK == CyBle_TpscGetCharacteristicValue(
                                          cyBle_connHandle,
                                          CYBLE_TPS_TX_POWER_LEVEL))
                {
                      DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
#endif /*CYBLE_TPS_CLIENT*/
            break;
#endif //ENABLE_PATH_LOSS_ALERT

        case BLE_CONFIG_HIDS_GET_INFO_VAL:
            {
                /*Read HID Information characteristic*/
                if(CYBLE_ERROR_OK == CyBle_HidscGetCharacteristicValue(
                                          cyBle_connHandle,
                                          CYBLE_HIDSC_READ_CHAR_VALUE,
                                          0,
                                          CYBLE_HIDS_INFORMATION))
                {
                       DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_HIDS_GET_RPT1_INDEX:
            {
                /*Set the report index zero, to start reading RRD*/
                reportIndex = CYBLE_HIDS_REPORT;
                if(CYBLE_ERROR_OK == CyBle_HidscGetCharacteristicDescriptor(cyBle_connHandle, 
                                        0, reportIndex++, CYBLE_HIDS_REPORT_RRD))
                {
                       DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_HIDS_GET_RPT2_INDEX:
            {
                if(CYBLE_ERROR_OK == CyBle_HidscGetCharacteristicDescriptor(cyBle_connHandle, 
                                        0, reportIndex++, CYBLE_HIDS_REPORT_RRD))
                {
                       DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_HIDS_GET_RPT3_INDEX:
            {
                if(CYBLE_ERROR_OK == CyBle_HidscGetCharacteristicDescriptor(cyBle_connHandle, 
                                        0, reportIndex++, CYBLE_HIDS_REPORT_RRD))
                {
                       DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_HIDS_GET_RPT4_INDEX:
            {
                if(CYBLE_ERROR_OK == CyBle_HidscGetCharacteristicDescriptor(cyBle_connHandle,
                                        0, reportIndex++, CYBLE_HIDS_REPORT_RRD))
                {
                       DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_HIDS_GET_RPT5_INDEX:
            {
                if(CYBLE_ERROR_OK == CyBle_HidscGetCharacteristicDescriptor(cyBle_connHandle, 
                                        0, reportIndex++, CYBLE_HIDS_REPORT_RRD))
                {
                       DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_HIDS_GET_RPT6_INDEX:
            {
                if(CYBLE_ERROR_OK == CyBle_HidscGetCharacteristicDescriptor(cyBle_connHandle, 
                                        0, reportIndex++, CYBLE_HIDS_REPORT_RRD))
                {
                       DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
            break;

        case BLE_CONFIG_SET_LL_ALERT_LVL:
#ifdef CYBLE_LLS_CLIENT
            {
                uint8  attrib = CYBLE_HIGH_ALERT;
                if(CYBLE_ERROR_OK == CyBle_LlscSetCharacteristicValue(
                                          cyBle_connHandle,
                                          CYBLE_LLS_ALERT_LEVEL,
                                          sizeof(attrib), &attrib))
                {
                    DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
#endif /*CYBLE_LLS_CLIENT*/
            break;

        case BLE_CONFIG_EN_SCAN_REFRESH_NOTIF:
#ifdef CYBLE_SCPS_CLIENT
            {
                uint16 attrValue = CYBLE_CCCD_NOTIFICATION;

                if(CYBLE_ERROR_OK == CyBle_ScpscSetCharacteristicDescriptor(
                                        cyBle_connHandle, CYBLE_SCPS_SCAN_REFRESH,
                                        CYBLE_SCPS_SCAN_REFRESH_CCCD,
                                        sizeof(attrValue), (uint8 *)&attrValue))
                {
                    DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
#endif /*CYBLE_SCPS_CLIENT*/
            break;

        case BLE_CONFIG_EN_BAT_LVL_NOTIF:
#ifdef CYBLE_BAS_CLIENT
            {
                uint16 attrValue = CYBLE_CCCD_NOTIFICATION;
                
                if(CYBLE_ERROR_OK == CyBle_BascSetCharacteristicDescriptor(
                            cyBle_connHandle, 0, CYBLE_BAS_BATTERY_LEVEL,
                            CYBLE_BAS_BATTERY_LEVEL_CCCD,
                            sizeof(attrValue), (uint8 *)&attrValue ))
                {
                    DongleBleState = DONGLE_BLE_STATE_BUSY;
                }
                else
                {
                    DongleBleAssert();
                }
            }
#endif /*CYBLE_BAS_CLIENT*/
            break;

        case BLE_CONFIG_HIDS_MOUSE_RPT_EN_NOTIF:
            {
                if(CYBLE_HIDS_REPORT <= report_Map_Table[MOUSE_IN_REPORT].charIndex)
                {
                    EnableHidscNotif(0, report_Map_Table[MOUSE_IN_REPORT].charIndex);
                }
            }
            break;  

        case BLE_CONFIG_HIDS_KB_RPT_EN_NOTIF:
            {
                if(CYBLE_HIDS_REPORT <= report_Map_Table[KEYBOARD_IN_REPORT].charIndex)
                {
                    EnableHidscNotif(0, report_Map_Table[KEYBOARD_IN_REPORT].charIndex);
                }
            }
            break;

        case BLE_CONFIG_HIDS_MULTI_RPT_EN_NOTIF:
            {
                if(CYBLE_HIDS_REPORT <= report_Map_Table[MULTIMEDIA_IN_REPORT].charIndex)
                {
                    EnableHidscNotif(0, report_Map_Table[MULTIMEDIA_IN_REPORT].charIndex);
                }
            }
            break;

        case BLE_CONFIG_HIDS_PWR_RPT_EN_NOTIF:
            {
                if(CYBLE_HIDS_REPORT <= report_Map_Table[POWER_IN_REPORT].charIndex)
                {
                    EnableHidscNotif(0, report_Map_Table[POWER_IN_REPORT].charIndex);
                }
            }
            break;
            
        case BLE_CONFIG_HIDS_GAMEPAD_RPT_EN_NOTIF:
            {
                if(CYBLE_HIDS_REPORT <= report_Map_Table[GAMEPAD_IN_REPORT].charIndex)
                {
                    EnableHidscNotif(0, report_Map_Table[GAMEPAD_IN_REPORT].charIndex);
                }
            }
            break;
#ifdef AUDIO_OVER_HID
        case BLE_CONFIG_HIDS_AUDIO_RPT_EN_NOTIF:
            {
                if(CYBLE_HIDS_REPORT <= report_Map_Table[AUDIO_IN_REPORT].charIndex)
                {
                    EnableHidscNotif(0, report_Map_Table[AUDIO_IN_REPORT].charIndex);
                }
            }
            break;

        case BLE_CONFIG_HIDS_AUDIO_SIGNAL_RPT_EN_NOTIF:
            {
                if(CYBLE_HIDS_REPORT <= report_Map_Table[AUDIO_SIGNAL_REPORT].charIndex)
                {
                    EnableHidscNotif(0, report_Map_Table[AUDIO_SIGNAL_REPORT].charIndex);
                }
            }
            break;
#endif /*AUDIO_OVER_HID*/

        default:
           break;
    }
}

/*****************************************************************************
* Function Name: IsHidServiceSupported()
******************************************************************************
* Summary:
* This function checks if the advt report contains HID service.
*
* Parameters:
* CYBLE_GAPC_ADV_REPORT_T*
*
* Return:
* bool - returns True if the report packet contains HID service UUID
*
* Theory:
* None
* 
* Side Effects:
* None
* 
*****************************************************************************/
static bool IsHidServiceSupported(CYBLE_GAPC_ADV_REPORT_T* scanReport)
{
    uint16 byteindex;

    for(byteindex = 0; byteindex <  scanReport->dataLen; )
    {
        /*Each advt data element contains: Length + Type + Data*/
        uint8 advStructureSize = scanReport->data[byteindex];
        if(advStructureSize)
        {
            /*Check the type of Adv Data*/
            uint8 advStructureType =
                           scanReport->data[byteindex + sizeof(advStructureSize)];
            /*HID service can be available in one of the below formats*/
            if ((CYBLE_GAP_ADV_INCOMPL_16UUID == advStructureType) ||
                (CYBLE_GAP_ADV_COMPL_16UUID == advStructureType) ||
                (CYBLE_GAP_ADV_SOLICIT_16UUID == advStructureType))
            {
                /*Point to Adv structure data*/
                uint8 UuidIndex = byteindex + sizeof(advStructureSize) + sizeof(advStructureType);
                /*Parse the list of UUIDs and check for HID service*/
                while(UuidIndex < (byteindex + advStructureSize))
                {
                    if(CYBLE_UUID_HIDS_SERVICE == CyBle_Get16ByPtr(&scanReport->data[UuidIndex]))
                    {
                        #ifdef COMP_ID_ADDR_FILTER
                        if((scanReport->peerBdAddr[3] == 0x50u) && (scanReport->peerBdAddr[4] == 0xA0u) &&
                            (scanReport->peerBdAddr[5] == 0x00u) && (CYBLE_GAP_ADDR_TYPE_PUBLIC == scanReport->peerAddrType))
                            {
                                return true;
                            }
                        #else
                            return true;
                        #endif
                    }
                    /*Check next UUID*/
                    UuidIndex += CYBLE_GATT_16_BIT_UUID_SIZE;
                }
            }
            /*Move to next AD structure*/
            byteindex += (advStructureSize + sizeof(uint8));
        }
        else
        {
            return false;
        }
    }
    return false;
}

/*****************************************************************************
* Function Name: FilterScanResponsePackets()
******************************************************************************
* Summary:
* This function stops further scanning if a HID device is found.
*
* Parameters:
* CYBLE_GAPC_ADV_REPORT_T*
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* Updates the flag "hidDeviceFound"
* 
*****************************************************************************/
static void FilterScanResponsePackets(CYBLE_GAPC_ADV_REPORT_T* scanReport)
{
    if(NULL == scanReport)
    {
        return;
    }

    /*Check if it is directed adv packet else, check if device contains HID service*/
    if((CYBLE_GAPC_CONN_DIRECTED_ADV == scanReport->eventType) ||
        (IsHidServiceSupported(scanReport)))
    {
        /*Copy the detected BD addr and set the device found flag*/
        memcpy(detectedServerAddr.bdAddr, scanReport->peerBdAddr,
               sizeof(detectedServerAddr.bdAddr));
        detectedServerAddr.type = scanReport->peerAddrType;
        hidDeviceFound = true;
#ifdef EN_WAIT_FOR_SCAN_RSP
        /*Wait for scan response*/
        isScanRspOccured = false;
#else
        CyBle_GapcStopScan();
#endif /*EN_WAIT_FOR_SCAN_RSP*/
    }
    
    if(scanReport->rssi < -70)
    {
      hidDeviceFound = false;
    }

#ifdef EN_WAIT_FOR_SCAN_RSP
    /*Check if the scan reponse occured for detected HID device*/
    if((CYBLE_GAPC_CONN_DIRECTED_ADV == scanReport->eventType) ||
        ((CYBLE_GAPC_SCAN_RSP == scanReport->eventType) && 
         (!memcmp(detectedServerAddr.bdAddr, scanReport->peerBdAddr, sizeof(detectedServerAddr.bdAddr)))))
    {
        /*Set this flag for directed ADV packets*/
        if(hidDeviceFound)
        {
            CyBle_GapcStopScan();
            isScanRspOccured = true;
        }
    }
#endif /*EN_WAIT_FOR_SCAN_RSP*/
}

/*****************************************************************************
* Function Name: SendEmptyReports()
******************************************************************************
* Summary:
* This function sends empty HID report packets to reset last key press events if any.
* Also it sends audio button control packet, to stop the audio data path
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* HID key reports required to be reset by sending UP key report, if any BLE disconnection happens.
*
* Side Effects:
* None
* 
*****************************************************************************/
static void SendEmptyReports(void)
{
    uint8 emptydata[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

    switch(lastSentReport)
    {
        case MOUSE_IN_REPORT:
            {
                /*Send empty mouse report*/
                emptydata[0] = MOUSE_REPORT_ID;
                CyS_SendEvent(HID_EP1_PACKET,0, 0, MOUSE_REPORT_SIZE, emptydata);
            }
            break;

        case KEYBOARD_IN_REPORT:
            {
                /*Send empty keyboard report*/
                CyS_SendEvent(HID_EP2_PACKET,0, 0, sizeof(emptydata), emptydata);
            }
            break;

        case MULTIMEDIA_IN_REPORT:
            {
                /*Send empty multimedia report*/
                emptydata[0] = MULTIMEDIA_REPORT_ID;
                CyS_SendEvent(HID_EP1_PACKET,0, 0, MULTIMEDIA_REPORT_SIZE, emptydata);
            }
            break;

        case POWER_IN_REPORT:
            {
                /*Send empty power report*/
                emptydata[0] = POWER_REPORT_ID;
                CyS_SendEvent(HID_EP1_PACKET,0, 0, POWER_REPORT_SIZE, emptydata);
            }
            break;

        default:
            {
                /*Do nothing, no active report is sent*/
            }
            break;
    }

#ifdef AUDIO_OVER_HID
    /*Send audio control packet to stop the audio data path*/
    audioControlOn = false;
    CyS_SendEvent(AUDIO_CONTROL_STATUS, 0, 0, sizeof(audioControlOn), (uint8*)&audioControlOn);
#endif /*AUDIO_OVER_HID*/

    /*Reset the flag once the last report is cleared*/
    lastSentReport = MAX_NUMBER_OF_REPORT_TYPES;
}

#ifdef ENABLE_PATH_LOSS_ALERT
/*****************************************************************************
* Function Name: Moving_average()
******************************************************************************
* Summary:
* This function implements the moving average algorithm for pre-configured number of samples.
*
* Parameters:
* currSample - Current sample to paas it via average filter
*
* Return:
* int8 - Sample after average filter applied
*
* Theory:
* RSSI values from the radio will have fluactuations which can trigger wrong alerts, 
* Averaging filter is used to smooth our the sudden jumpe in RSSI levels.
*
* Side Effects:
* None
* 
* Note:
* This function accumulates the sample until the required samples recieved, until then it returns the default value
*****************************************************************************/
static int8 Moving_average(int8 currSample)
{
    static uint8 currIndex = 0;
    int32 sampleSum = 0;
    uint8 sampleIndex = 0;

    if((NUMBER_OF_SAMPLES_TO_AVG - 1) == currIndex)
    {
        currIndex = 0;
    }
    rssiSamples[currIndex++] = currSample;

    /*Sum the recent samples*/
    for(sampleIndex = 0; sampleIndex < NUMBER_OF_SAMPLES_TO_AVG; sampleIndex++)
    {
        sampleSum += rssiSamples[sampleIndex];
    }

    /*Return the average value*/
    return((int8)(sampleSum/(int8)NUMBER_OF_SAMPLES_TO_AVG));
}

/*****************************************************************************
* Function Name: Monitor_Path_Loss()
******************************************************************************
* Summary:
* This function monitors path loss and sets\resets immediate alert level Proximity reporter.
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
* 
*****************************************************************************/
static void Monitor_Path_Loss(void)
{
    static bool isDeviceAlerted = false;

    if (rxPathLoss < RSSI_THRESHOLD_VALUE)
    {
        if (isDeviceAlerted)
        {
            if(CYBLE_ERROR_OK == Set_Ias_AlertLevel(CYBLE_NO_ALERT))
            {
                isDeviceAlerted = false;
            }
        }
    }
    else
    {
        /*Set alert when the path loss is below threshold*/
        if(!isDeviceAlerted)
        {
            if(CYBLE_ERROR_OK == Set_Ias_AlertLevel(CYBLE_HIGH_ALERT))
            {
                isDeviceAlerted = true;
                rxPathLoss = RSSI_THRESHOLD_VALUE - 1;
            }
        }
    }
}
#endif //ENABLE_PATH_LOSS_ALERT

/*****************************************************************************
* Function Name: Dongle_Ble_State_Handler()
******************************************************************************
* Summary:
* This function handles application state machine for BLE component.
* The states include scanning, connection, GATT Discovery, Pairing and Profile level configuration etc.
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
* 
* Side Effects:
* None
* 
*****************************************************************************/
void Dongle_Ble_State_Handler(void)
{      
    CYBLE_GAP_BONDED_DEV_ADDR_LIST_T bondedDevList;

    if (CYBLE_STACK_STATE_BUSY == CyBle_GattGetBusStatus())
    {
        /*If stack is busy wait for ready signal*/
        return;
    }

    if(terminateLink)
    {
        BLE_Disconnect();
    }

    CyBle_ProcessEvents();
    switch(DongleBleState)
    {
        /* BLE component will be in this state until the GATT discovery is complete on connected peripheral*/
        case DONGLE_BLE_STATE_NOT_READY:
            if(CYBLE_STATE_DISCONNECTED == CyBle_GetState())
            {
#ifdef EN_WAIT_FOR_SCAN_RSP
                if(hidDeviceFound & isScanRspOccured)
#else
                if(hidDeviceFound)
#endif /*EN_WAIT_FOR_SCAN_RSP*/
                {
                    hidDeviceFound = false;
                    if(CYBLE_ERROR_OK != CyBle_GapcConnectDevice(&detectedServerAddr))
                    {
                        DongleBleAssert();
                    }
                }
                else
                {
                    if(isButtonTriggered)
                    {
                        /*As single device is supported, clear complete bond list*/
                        CYBLE_GAP_BD_ADDR_T peerBDAddr = {{0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u}, 0x00u };
                        if(CYBLE_ERROR_OK != CyBle_GapRemoveDeviceFromWhiteList(&peerBDAddr))
                        {
                            DongleBleAssert();
                        }

                        bondedDevList.count = 0;
                        (void)CyBle_GapGetBondedDevicesList(&bondedDevList);

                        /*Wait for bond info clean-up*/
                        if(0 == bondedDevList.count)
                        {
                            /*Start scanning with-out whitelist filter*/
                            cyBle_discoveryInfo.scanFilterPolicy = CYBLE_GAPC_ADV_ACCEPT_ALL_PKT;
                            StartDeviceScanning();
                        }
                        terminateLink = false;
                    }
                    else
                    {
                        bondedDevList.count = 0;
                        (void)CyBle_GapGetBondedDevicesList(&bondedDevList);
#if 0
                        /*Use white-list by default, if bonded devices present*/
                        if(0 != bondedDevList.count)
                        {
                            /*Before connecting to new device, remove oldest entry from the list, if it is already full*/
                            /*HID Dongle supports maximum of "CYBLE_GAP_MAX_BONDED_DEVICE-1" devices to be bonded*/
                            if(CYBLE_GAP_MAX_BONDED_DEVICE == bondedDevList.count)
                            {
                                if(CYBLE_ERROR_OK != CyBle_GapRemoveOldestDeviceFromBondedList())
                                {
                                    DongleBleAssert();
                                }
                            }

                            cyBle_discoveryInfo.scanFilterPolicy = CYBLE_GAPC_ADV_ACCEPT_WHITELIST_PKT;
                            StartDeviceScanning();
                            terminateLink = false;
                        }
                        else
#endif
                        {
                            /*Do nothing, device is waiting for bind button press*/
                            Led_Stop();
                            if(terminateLink)
                            {
                                /*Re-start scanning as disconnect happened due to error*/
                                cyBle_discoveryInfo.scanFilterPolicy = CYBLE_GAPC_ADV_ACCEPT_ALL_PKT;
                                StartDeviceScanning();
                                terminateLink = false;
                            }
                        }
                    }
                }
            }
            else if(CYBLE_STATE_SCANNING == CyBle_GetState())
            {
                /*Keep blinking while scanning, blink rate is as per scanning mode*/
                if(CYBLE_GAPC_ADV_ACCEPT_ALL_PKT == cyBle_discoveryInfo.scanFilterPolicy)
                {
                    if(Led_IsComplete())
                    {
                        Device_Led_Fast_Blinking();
                    }
                    /*Reset the button press flag, if current scan mode is ignoring the white-list*/
                    isButtonTriggered = false;
                }
                else
                {
                    if(Led_IsComplete())
                    {
                        Device_Led_Slow_Blinking();
                    }
                }
            }
            else
            {
                Led_Stop();
            }

            if(CYBLE_CLIENT_STATE_CONNECTED == CyBle_GetClientState())
            {
                /*Check if current device is pre-bonded and configured once*/
                (void)CyBle_GapGetBondedDevicesList(&bondedDevList);
                if((!memcmp(&detectedServerAddr, &bondedDevList.bdAddrList[0], sizeof(detectedServerAddr))) &&
                    (bondedDevList.count) && (CYBLE_CLIENT_STATE_DISCONNECTED_DISCOVERED == CyBle_GetClientState()))
                {
                    /*Skip GATT discovery for pre-bonded discovered device*/
                    CyBle_SetClientState(CYBLE_CLIENT_STATE_DISCOVERED);
                }
                else
                {
                    /*Discover all server DB items*/
                    if(CYBLE_ERROR_OK != CyBle_GattcStartDiscovery(cyBle_connHandle))
                    {
                        /*Assert if unable to start discovery*/
                        DongleBleAssert();
                    }
                }
            }
            else if(CYBLE_CLIENT_STATE_DISCOVERED == CyBle_GetClientState())
            {
                /*Check if current device is pre-bonded and configured once*/
                (void)CyBle_GapGetBondedDevicesList(&bondedDevList);
                if((!memcmp(&detectedServerAddr, &bondedDevList.bdAddrList[0], sizeof(detectedServerAddr))) &&
                    (bondedDevList.count) && (CYBLE_HIDS_PROTOCOL_MODE != report_Map_Table[KEYBOARD_IN_REPORT].charIndex))
                {
                    /*For pre-bonded devices, no need of repeating configuartion*/
                    skipProfileConfig = true;
                }
                else
                {
                    /*Reset the report mapping with report IDs on each connection*/
                    memset(&report_Map_Table, 0, sizeof(report_Map_Table));
                    /*Initialize the table with expected report IDs from HID server*/
                    report_Map_Table[MOUSE_IN_REPORT].ReportId        = MOUSE_REPORT_ID;
                    report_Map_Table[KEYBOARD_IN_REPORT].ReportId     = KEYBOARD_REPORT_ID;
                    report_Map_Table[MULTIMEDIA_IN_REPORT].ReportId   = MULTIMEDIA_REPORT_ID;
                    report_Map_Table[POWER_IN_REPORT].ReportId        = POWER_REPORT_ID;
                    report_Map_Table[GAMEPAD_IN_REPORT].ReportId      = GAMEPAD_REPORT_ID;
#ifdef AUDIO_OVER_HID
                    report_Map_Table[AUDIO_IN_REPORT].ReportId        = AUDIO_REPORT_ID;
                    report_Map_Table[AUDIO_SIGNAL_REPORT].ReportId    = AUDIO_SIGNAL_REPORT_ID;
#endif /*AUDIO_OVER_HID*/
                    skipProfileConfig = false;
                }

                /*Configure the device on each connection*/
                currentConfigState = TOTAL_NUM_CONFIG_REQUESTS;
                DongleBleState = DONGLE_BLE_STATE_CONFIG;
            }
            break;/*End of  case DONGLE_BLE_STATE_NOT_READY:*/

        /*BLE component is ready to process new commands*/
        case DONGLE_BLE_STATE_ACTIVE:
            /*Reset the application state, if BLE is not in discovered state*/
            if(CYBLE_CLIENT_STATE_DISCOVERED != CyBle_GetClientState())
            {
                DongleBleState = DONGLE_BLE_STATE_NOT_READY;
            }
            else
            {
#ifdef ENABLE_PATH_LOSS_ALERT
                Monitor_Path_Loss();
#endif //ENABLE_PATH_LOSS_ALERT
            }

            /*Switch ON the LED, should be off when disconnection occurs*/
            Device_Led_On_Continous();

#ifdef AUDIO_OVER_HID
            /*Handle the lost audio control stop packet if any*/
#ifdef EN_AUDIO_CONTROL_TIMEOUT
            if(audioControlOn)
            {
                /*Send the audio control stop packet on timeout*/
                if(Timer_Time_Elapsed(audioCntrlTimeStamp, AUDIO_CONTROL_TIMEOUT))
                {
                    /*Send audio control packet to stop the audio data path*/
                    audioControlOn = false;
                    CyS_SendEvent(AUDIO_CONTROL_STATUS, 0, 0, sizeof(audioControlOn), (uint8*)&audioControlOn);
                }
            }
#endif /*EN_AUDIO_CONTROL_TIMEOUT*/

#endif /*AUDIO_OVER_HID*/
            /*Enter into sleep mode when the device is idle*/
            {
                CYBLE_BLESS_STATE_T blessState = CYBLE_BLESS_STATE_ACTIVE;
                CYBLE_LP_MODE_T pwrState = CyBle_EnterLPM(CYBLE_BLESS_SLEEP);

                CyGlobalIntDisable;
                blessState = CyBle_GetBleSsState();

                if(pwrState == CYBLE_BLESS_SLEEP)
                {
                    if(blessState != CYBLE_BLESS_STATE_EVENT_CLOSE)
                    {
                        CySysPmSleep();
                    }
                }
                CyGlobalIntEnable;
            }
            break;

        /*BLE component is processing current command*/
        case DONGLE_BLE_STATE_BUSY:
            /*BLE component is processing current command*/

            /*Reset the application state, if BLE is not in discovered state*/
            if(CYBLE_CLIENT_STATE_DISCOVERED != CyBle_GetClientState())
            {
                DongleBleState = DONGLE_BLE_STATE_NOT_READY;
            }
            break;

        /*Connected device being configured for operation*/
        case DONGLE_BLE_STATE_CONFIG:
            /*Reset the application state, if BLE is not in discovered state*/
            if(CYBLE_CLIENT_STATE_DISCOVERED != CyBle_GetClientState())
            {
                DongleBleState = DONGLE_BLE_STATE_NOT_READY;
            }
            else if(BLE_CONFIG_COMPLETED != currentConfigState)
            {
                DongleBleConfig();
            }
            else
            {
                /*Exit the state if all the configurations are complete*/
                DongleBleState = DONGLE_BLE_STATE_ACTIVE;
            }
           break;

        default:
           break;
    }

    /*On button press disconnect if connection exist and re-start scanning without white-list*/
    if(isButtonTriggered)
    {
        if(CYBLE_STATE_CONNECTED == CyBle_GetState())
        {
            /*Issue disconnect for already connected device*/
            terminateLink = true;
        }
        else if(CYBLE_STATE_CONNECTING == CyBle_GetState())
        {
            /*Cancel the connection, if it is in progress*/
            if(CYBLE_ERROR_OK != CyBle_GapcCancelDeviceConnection())
            {
                DongleBleAssert();
            }
        }
        else if(CYBLE_STATE_SCANNING == CyBle_GetState())
        {
            if(CYBLE_GAPC_ADV_ACCEPT_ALL_PKT != cyBle_discoveryInfo.scanFilterPolicy)
            {
                /*Restart the scanning*/
                CyBle_GapcStopScan();
                /*Flag will be cleared when normal scanning is initiated successfully*/
                cyBle_discoveryInfo.scanFilterPolicy = CYBLE_GAPC_ADV_ACCEPT_ALL_PKT;
            }
        }
    }
}

/*****************************************************************************
* Function Name: BleCallBack()
******************************************************************************
* Summary:
* Callback function for generic BLE stack events.
*
* Parameters:
* uint32 event
* void*  eventParam
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* Modifies  DongleBleState
* 
*****************************************************************************/
static void BleCallBack(uint32 event, void* eventParam)
{
    switch(event)
    {
        case CYBLE_EVT_STACK_ON:
            {
                CYBLE_BLESS_CLK_CFG_PARAMS_T bleSSClkConfig;
                if(CYBLE_ERROR_OK == CyBle_GetBleClockCfgParam(&bleSSClkConfig))
                {
                    bleSSClkConfig.bleLlSca = CYBLE_LL_SCA_101_TO_150_PPM;
                    CyBle_SetBleClockCfgParam(&bleSSClkConfig);
                }
            }
            break;

        case CYBLE_EVT_HARDWARE_ERROR:
        case CYBLE_EVT_HCI_STATUS:
            {
                /*Assert if any unexpected errors*/
                DongleBleAssert();
            }
            break;

        case CYBLE_EVT_TIMEOUT:
            /*Issue disconnect on any GATT timeout*/
            if(CYBLE_GATT_RSP_TO == (CYBLE_TO_REASON_CODE_T)*(uint8 *)eventParam)
            {
                terminateLink = true;
                /*Reset the config state, to proceed with disconnection*/
                currentConfigState = TOTAL_NUM_CONFIG_REQUESTS;
            }
            break;

        case CYBLE_EVT_GAPC_SCAN_PROGRESS_RESULT:
            {
                /*Check if device meets the dongle requirements*/
                FilterScanResponsePackets((CYBLE_GAPC_ADV_REPORT_T *)eventParam);
            }
            break;

        case CYBLE_EVT_GAP_DEVICE_DISCONNECTED:
            {
                /*Switch OFF the LED, should be off when Disconnected*/
                Led_Stop();
                /*Reset bond status of BLE link*/
                isBonded = CYBLE_GAP_BONDING_NONE;
#ifdef ENABLE_PATH_LOSS_ALERT
                /*Reset the recorded RSSI samples on disconnection*/
                memset(rssiSamples, -(RSSI_THRESHOLD_VALUE), sizeof(rssiSamples));
#endif //ENABLE_PATH_LOSS_ALERT

                /*Send empty report packets when active device is disconnected*/
                SendEmptyReports();
                /*Start the scanning even if no bond-info exist*/
                terminateLink = true;
            }
            break;

        case CYBLE_EVT_GATTC_XCHNG_MTU_RSP:
            {
                DongleBleState = DONGLE_BLE_STATE_CONFIG;
            }
            break;

        case CYBLE_EVT_GAP_AUTH_COMPLETE:
            {
                CYBLE_GAP_AUTH_INFO_T *authInfo = (CYBLE_GAP_AUTH_INFO_T*)eventParam;

                isBonded = authInfo->bonding;
                DongleBleState = DONGLE_BLE_STATE_CONFIG;
            }
            break;

        case CYBLE_EVT_GAP_AUTH_FAILED:
            {
                /*Issue disconnect on Auth failure*/
                terminateLink = true;
                /*Reset the config state, to proceed with disconnection*/
                currentConfigState = TOTAL_NUM_CONFIG_REQUESTS;

                /*Issue disconnect and clear bond info, as permission error occurs*/
                if((CYBLE_GAP_AUTH_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE == (*(CYBLE_GAP_AUTH_FAILED_REASON_T*)eventParam))
                    || (CYBLE_GAP_AUTH_ERROR_CONFIRM_VALUE_NOT_MATCH == (*(CYBLE_GAP_AUTH_FAILED_REASON_T*)eventParam)))
                {
                    /*Set the button triggered flag, which will be used to clear the bond list*/
                    isButtonTriggered = true;
                }
            }
            break;

        case CYBLE_EVT_GATTC_READ_RSP:
            {
                CYBLE_GATTC_READ_RSP_PARAM_T *readResp = (CYBLE_GATTC_READ_RSP_PARAM_T *)eventParam;
                if(BLE_CONFIG_GET_PREF_CONN_PARAMS == currentConfigState)
                {
                    memcpy(&prefConnParams, readResp->value.val, sizeof(prefConnParams));
                    DongleBleState = DONGLE_BLE_STATE_CONFIG;
                }
            }
            break;

        case CYBLE_EVT_GATTC_ERROR_RSP:
            {
                CYBLE_GATTC_ERR_RSP_PARAM_T *GattErrResp = (CYBLE_GATTC_ERR_RSP_PARAM_T *)eventParam;

                /*Issue disconnect and clear bond info, as permission error occurs*/
                if((CYBLE_GATT_ERR_INSUFFICIENT_AUTHENTICATION == GattErrResp->errorCode)
                      || (CYBLE_GATT_ERR_INSUFFICIENT_AUTHORIZATION == GattErrResp->errorCode)
                      || (CYBLE_GATT_ERR_INSUFFICIENT_ENC_KEY_SIZE == GattErrResp->errorCode)
                      || (CYBLE_GATT_ERR_INSUFFICIENT_ENCRYPTION == GattErrResp->errorCode))
                {
                    /*Set the button triggered flag, which will be used to clear the bond list*/
                    isButtonTriggered = true;
                }
            }
            break;

        case CYBLE_EVT_GATTC_SRVC_DISCOVERY_FAILED:
        case CYBLE_EVT_GATTC_INCL_DISCOVERY_FAILED:
        case CYBLE_EVT_GATTC_CHAR_DISCOVERY_FAILED:
        case CYBLE_EVT_GATTC_DESCR_DISCOVERY_FAILED:
            {
                /*Issue disconnect, as discovery is failed*/
                terminateLink = true;
            }
            break;

        case CYBLE_EVT_L2CAP_CONN_PARAM_UPDATE_REQ:
            {
                uint16 result = CYBLE_L2CAP_CONN_PARAM_REJECTED;

                /*Accept new connection parameter request from device, only after configuration is completed*/
                if(DONGLE_BLE_STATE_ACTIVE == DongleBleState)
                {
                    result = CYBLE_L2CAP_CONN_PARAM_ACCEPTED;
                }

                if(CYBLE_ERROR_OK != CyBle_L2capLeConnectionParamUpdateResponse(cyBle_connHandle.bdHandle, result))
                {
                    DongleBleAssert();
                }
            }
            break;
    }/*End of switch(event)*/
}

#ifdef CYBLE_BAS_CLIENT
/*****************************************************************************
* Function Name: BasCallBack()
******************************************************************************
* Summary:
* Callback function to process events for BAS
*
* Parameters:
* uint32 event
* void *eventParam
*
* Return:
* None
*
* Theory:
* None
* 
* Side Effects:
* Modifies  DongleBleState 
*
*****************************************************************************/
static void BasCallBack (uint32 event, void *eventParam)
{
    if (CYBLE_EVT_BASC_NOTIFICATION == event)
    {
        CYBLE_BAS_CHAR_VALUE_T *BatteryValue = (CYBLE_BAS_CHAR_VALUE_T *)eventParam;
        uint8 batReportID = BATTERY_FEATURE_REPORT_ID;

        /*Send battery level as feature report in mouse interface*/
        /*Send battery report ID, followed by the battery value*/
        if(BATTERY_FEATURE_REPORT_SIZE == BatteryValue->value->len)
        {
            CyS_SendEvent(HID_EP1_PACKET, 0, BatteryValue->value->len,
                sizeof(batReportID), &batReportID);
            TransmitAdditionalData(BatteryValue->value->val, BATTERY_FEATURE_REPORT_SIZE);
        }
    }
    else if(CYBLE_EVT_BASC_WRITE_DESCR_RESPONSE == event)
    {
        /*Move to next configuration*/  
        DongleBleState = DONGLE_BLE_STATE_CONFIG; 
    }
}
#endif /*CYBLE_BAS_CLIENT*/

#ifdef ENABLE_PATH_LOSS_ALERT
#ifdef CYBLE_TPS_CLIENT
/*****************************************************************************
* Function Name: TpsCallBack()
******************************************************************************
* Summary:
* Callback function to process events for TPS
*
* Parameters:
* uint32 event
* void *eventParam
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* Modifies  DongleBleState and Tx_Power_Level
* 
*****************************************************************************/ 
static void TpsCallBack (uint32 event, void *eventParam)
{
    if(CYBLE_EVT_TPSC_READ_CHAR_RESPONSE == event)
    {
        CYBLE_TPS_CHAR_VALUE_T *tpsValue = (CYBLE_TPS_CHAR_VALUE_T *)eventParam;
        /*Read TX level on every new connection*/
        if(0 != tpsValue->value->len)
        {
            Tx_Power_Level = *(tpsValue->value->val);
        }
        DongleBleState = DONGLE_BLE_STATE_CONFIG;
    }
}
#endif /*CYBLE_TPS_CLIENT*/
#endif //ENABLE_PATH_LOSS_ALERT

#ifdef CYBLE_HIDS_CLIENT
/*****************************************************************************
* Function Name: HidsCallBack()
******************************************************************************
* Summary:
* Callback function to process events for HID
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* Modifies hidsReportMapUsage, DongleBleState
* 
*****************************************************************************/    
static void HidsCallBack (uint32 event, void *eventParam)
{
    uint8 len;
    switch(event)
    {
        case CYBLE_EVT_HIDSC_NOTIFICATION:
            {
#ifdef ENABLE_PATH_LOSS_ALERT
                /*Check signal strength of last received packet*/
                rxPathLoss = Tx_Power_Level - Moving_average(CyBle_GetRssi());
#endif //ENABLE_PATH_LOSS_ALERT

                if(DONGLE_BLE_STATE_ACTIVE == DongleBleState)
                {
                    CYBLE_HIDS_CHAR_VALUE_T *hidNotifVal = (CYBLE_HIDS_CHAR_VALUE_T*)eventParam;
                    REPORT_ID_T idIndex = MOUSE_IN_REPORT;

                    /*Send wake-up signal, if device is in suspend mode*/
                    if(dongleSuspend)
                    {
                        Pin_RemoteWakeup_Write(0);
                        dongleSuspend = false;
                    }

                    for(idIndex = MOUSE_IN_REPORT; idIndex < MAX_NUMBER_OF_REPORT_TYPES; idIndex++)
                    {
                        /*Check if the notification report index matches to any one of the expected report ID*/
                        if(report_Map_Table[idIndex].charIndex == hidNotifVal->charIndex)
                        {
                            switch(idIndex)
                            {
                                case MOUSE_IN_REPORT:
                                    if(MOUSE_REPORT_SIZE > hidNotifVal->value->len)
                                    {
                                        /*Send report ID followed by the report data for mouse end point*/
                                        uint8 mouseReport[] = {MOUSE_REPORT_ID, 0x00, 0x00, 0x00, 0x00, 0x00};
                                        /*Copy the mouse data from HID notification*/
                                        memcpy(&mouseReport[1], hidNotifVal->value->val, hidNotifVal->value->len);
                                        CyS_SendEvent(HID_EP1_PACKET, 0, 0, sizeof(mouseReport), mouseReport);
                                    }
                                    break;

                                case KEYBOARD_IN_REPORT:
                                    {
                                        /*Report ID not required for keyboard end point, send the complete report data*/
                                        uint8 keyboardReport[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

                                        memcpy(keyboardReport, hidNotifVal->value->val,hidNotifVal->value->len);
                                   
                                        CyS_SendEvent(HID_EP2_PACKET, 0, 0, sizeof(keyboardReport), keyboardReport);
                                    }
                                    break;

                                case MULTIMEDIA_IN_REPORT:
                                    if(MULTIMEDIA_REPORT_SIZE > hidNotifVal->value->len)
                                    {
                                        /*Send report ID followed by the report data for mouse end point*/
                                        uint8 multiMediaReport[] = {MULTIMEDIA_REPORT_ID, 0x00, 0x00};
                                        /*Copy the report data from HID notification*/
                                        memcpy(&multiMediaReport[1], hidNotifVal->value->val, hidNotifVal->value->len);
                                        
#ifdef CHANGE_VOLUME_KEY
                                        static uint8 change_volume_send = 0;
                                        /*Report ID not required for keyboard end point, send the complete report data*/
                                        uint8 keyboardReport[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
                                        //len = sizeof(keyboardReport);
                                        
                                        //memcpy(keyboardReport, hidNotifVal->value->val,len);
                                        
                                        if(multiMediaReport[1] == 0xE9)
                                        {
                                          // +
                                          change_volume_send = 1;
                                          //memset(keyboardReport, 0,len);
                                          keyboardReport[2] = 0x3A;
                                          CyS_SendEvent(HID_EP2_PACKET, 0, 0, sizeof(keyboardReport), keyboardReport);
                                        }
                                        else if(multiMediaReport[1] == 0xEA)
                                        {
                                          // -
                                          change_volume_send = 1;
                                          keyboardReport[2] = 0x3B;
                                          CyS_SendEvent(HID_EP2_PACKET, 0, 0, sizeof(keyboardReport), keyboardReport);
                                        }
                                        else if(change_volume_send)
                                        {
                                           change_volume_send = 0;
                                          CyS_SendEvent(HID_EP2_PACKET, 0, 0, sizeof(keyboardReport), keyboardReport);
                                        }
                                        else
#endif                            
                                        {
                                           CyS_SendEvent(HID_EP1_PACKET, 0, 0, sizeof(multiMediaReport), multiMediaReport);
                                        }
                                        

                                       
                                    }
                                    break;

                                case POWER_IN_REPORT:
                                    if(POWER_REPORT_SIZE > hidNotifVal->value->len)
                                    {
                                        /*Send report ID followed by the report data for mouse end point*/
                                        uint8 powerReport[] = {POWER_REPORT_ID, 0x00};
                                        /*Copy the report data from HID notification*/
                                        memcpy(&powerReport[1], hidNotifVal->value->val, hidNotifVal->value->len);
                                        CyS_SendEvent(HID_EP1_PACKET, 0, 0, sizeof(powerReport), powerReport);
                                    }
                                    break;
#ifdef SUPPORT_GAMEPAD_KEY 
                                case GAMEPAD_IN_REPORT:
                                    {
                                        /*Report ID not required for keyboard end point, send the complete report data*/
                                        uint8 keyboardReport[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
                                        len = sizeof(keyboardReport);
                                        
                                        memcpy(keyboardReport, hidNotifVal->value->val,len);
                                        
                                        if(keyboardReport[6] == 0x1)
                                        {
                                          // ok
                                          memset(keyboardReport, 0,len);
                                          keyboardReport[2] = 0x28;
                                        }
                                        else if(keyboardReport[6] == 0x2)
                                        {
                                          // return
                                          memset(keyboardReport, 0,len);
                                          keyboardReport[2] = 0x29;
                                        }
                                        else if(keyboardReport[6] == 0x10)
                                        {
                                          //menu
                                          memset(keyboardReport, 0,len);
                                          keyboardReport[2] = 0x65;
                                        }
                                        else if(keyboardReport[0]==0x80 && keyboardReport[1]== 0xFF)
                                        {
                                          // down
                                          memset(keyboardReport, 0,len);
                                          keyboardReport[2] = 0x51;
                                        }
                                        else if(keyboardReport[0]==0x80 && keyboardReport[1]== 0x01)
                                        {
                                          // up
                                          memset(keyboardReport, 0,len);
                                          keyboardReport[2] = 0x52;
                                        }                 
                                        else if(keyboardReport[0]==0xff && keyboardReport[1]== 0x80)
                                        {
                                          // right
                                          memset(keyboardReport, 0,len);
                                          keyboardReport[2] = 0x4f;
                                        }
                                        else if(keyboardReport[0]==0x01 && keyboardReport[1]== 0x80)
                                        {
                                          // left
                                          memset(keyboardReport, 0,len);
                                          keyboardReport[2] = 0x50;
                                        }
                                        else
                                        {
                                          // no key
                                          memset(keyboardReport, 0,len);
                                        }
                                        CyS_SendEvent(HID_EP2_PACKET, 0, 0, sizeof(keyboardReport), keyboardReport);
                                    }
                                    break;
#endif

#ifdef AUDIO_OVER_HID
                                case AUDIO_IN_REPORT:
                                    /*Send Audio report*/
                                    {
                                        CyS_SendEvent(AUDIO_REPORT, 0, 0, hidNotifVal->value->len, hidNotifVal->value->val);
                                    }
#ifdef EN_AUDIO_CONTROL_TIMEOUT
                                    /*Get the new time stamp for each audio report*/
                                    audioCntrlTimeStamp = Timer_Get_Time_Stamp();
#endif /*EN_AUDIO_CONTROL_TIMEOUT*/
                                    break;

                                case AUDIO_SIGNAL_REPORT:
                                    /*Check if audio control packet and send control signal to P5LP*/
                                    if(AUDIO_CONTROL_ID  == hidNotifVal->value->val[AUDIO_ID_INDEX])
                                    {
                                        audioControlOn = (0 == hidNotifVal->value->val[AUDIO_VAL_INDEX]) ? false : true;
                                        CyS_SendEvent(AUDIO_CONTROL_STATUS, 0, 0, sizeof(audioControlOn), (uint8*)&audioControlOn);

                                    }
                                    else if(AUDIO_SYNC_ID  == hidNotifVal->value->val[AUDIO_ID_INDEX])
                                    {
                                        CyS_SendEvent(AUDIO_SYNC_PACKET, 0, 0, hidNotifVal->value->len - AUDIO_VAL_INDEX,
                                                      &hidNotifVal->value->val[AUDIO_VAL_INDEX]);

                                    }
                                    break;
#endif /*AUDIO_OVER_HID*/

                                default:
                                    /*Ignore other type of reports if any, the bridge controller HID report map doesnt support other types*/
                                    break;
                            }

                            /*Record the last sent report type, which can be used to reset the USB report on link disconnection*/
                            lastSentReport = idIndex;

                            /*Break out of loop, once the report ID is detected*/
                            break;
                        }
                    }
                }
            }
            break;

        case CYBLE_EVT_HIDSC_READ_DESCR_RESPONSE:
            {
                CYBLE_HIDS_DESCR_VALUE_T *descrVal = (CYBLE_HIDS_DESCR_VALUE_T*)eventParam;
                if(0 != descrVal->value->len)
                {
                    uint8 *rrdValue = descrVal->value->val;

                    if(CYBLE_HIDS_REPORT_TYPE_INPUT == rrdValue[HID_RRD_RTYPE_BYTE_INDEX])
                    {
                        /*Copy the report char index into corresponding report ID in the map*/
                        REPORT_ID_T idIndex = MOUSE_IN_REPORT;
                        for(idIndex = MOUSE_IN_REPORT; idIndex < MAX_NUMBER_OF_REPORT_TYPES; idIndex++)
                        {
                            if(report_Map_Table[idIndex].ReportId == rrdValue[HID_RRD_RID_BYTE_INDEX])
                            {
                                report_Map_Table[idIndex].charIndex = descrVal->charIndex;
                            }
                        }
                    }
                }
                DongleBleState = DONGLE_BLE_STATE_CONFIG;
            }
            break;

        case CYBLE_EVT_HIDSC_WRITE_DESCR_RESPONSE:
            {
                DongleBleState = DONGLE_BLE_STATE_CONFIG;
            }
            break;

        case CYBLE_EVT_HIDSC_READ_CHAR_RESPONSE:
            {
                CYBLE_HIDS_CHAR_VALUE_T *ReportmapVal = (CYBLE_HIDS_CHAR_VALUE_T*)eventParam;

                /*Process the received Information value*/
                if(CYBLE_HIDS_INFORMATION == ReportmapVal->charIndex)
                {
                    if(0 != ReportmapVal->value->len)
                    {
                        /*Parse and check if the wake-up flag is set in the flags field*/
                        if(CYBLE_HIDS_INFO_FLAG_REMOTE_WAKE_MASK | ReportmapVal->value->val[HID_INFO_FLAGS_BYTE_INDEX])
                        {
                            isWakeupCapable = true;
                        }
                        else
                        {
                            isWakeupCapable = false;
                        }
                    }
                    DongleBleState = DONGLE_BLE_STATE_CONFIG;
                }
                else
                {
                    /*Other HID attributes are not read*/
                }
            }
            break;

        default:
           /*Other Events. Not to be handled.*/
            break;
    }
}
#endif /*CYBLE_HIDS_CLIENT*/

#ifdef CYBLE_SCPS_CLIENT
/*****************************************************************************
* Function Name: ScpsCallBack()
******************************************************************************
* Summary:
* Callback function to process events for SCPS
*
* Parameters:
* uint32 event
* void *eventParam
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* Modifies DongleBleState
* 
*****************************************************************************/
static void ScpsCallBack(uint32 event, void *eventParam)
{
    /*Unused param*/
    (void)eventParam;

    if (CYBLE_EVT_SCPSC_NOTIFICATION == event)
    {
        uint8 attr[CYBLE_INTERVAL_WINDOW_CHAR_LEN];

        CyBle_Set16ByPtr(attr, CYBLE_FAST_SCAN_INTERVAL);
        CyBle_Set16ByPtr(&attr[sizeof(uint16)], CYBLE_FAST_SCAN_WINDOW);

        if(CYBLE_ERROR_OK != CyBle_ScpscSetCharacteristicValue(cyBle_connHandle,
                                                CYBLE_SCPS_SCAN_INT_WIN,
                                                sizeof(attr), attr))
        {
            DongleBleAssert();
        }
    }
    else if(CYBLE_EVT_SCPSC_WRITE_DESCR_RESPONSE == event)
    {
        DongleBleState = DONGLE_BLE_STATE_CONFIG;
    }
    else
    {
        /*Nothing to be done here as no other event is expected*/
    }
}
#endif /*CYBLE_SCPS_CLIENT*/

#ifdef CYBLE_LLS_CLIENT
/*****************************************************************************
* Function Name: LlsCallBack()
******************************************************************************
* Summary:
* Callback function to process events for LLS
*
* Parameters:
* uint32 event
* void *eventParam
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* Modifies DongleBleState
* 
*****************************************************************************/
static void LlsCallBack (uint32 event, void *eventParam)
{
    /*Unused param - below line added to remove the warnings*/
    (void)eventParam;

    if(CYBLE_EVT_LLSC_WRITE_CHAR_RESPONSE == event)
    {
        DongleBleState = DONGLE_BLE_STATE_CONFIG;
    }
}
#endif /*CYBLE_LLS_CLIENT*/

/*****************************************************************************
* Function Name: Process_Suspend_Command()
******************************************************************************
* Summary:
* This function puts system into low power mode, on suspend command.
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
* 
*****************************************************************************/
void Process_Suspend_Command(void)
{
    /*Flag is used to avoid multiple calls to set device Control Point*/
    static bool isPeripheralSuspended = false;

    CYBLE_BLESS_STATE_T blessState = CYBLE_BLESS_STATE_ACTIVE;
    CYBLE_LP_MODE_T pwrState;

    /*Stop scanning before entering sleep mode*/
    if(CYBLE_STATE_SCANNING == CyBle_GetState())
    {
        CyBle_GapcStopScan();
    }
    else if(DONGLE_BLE_STATE_NOT_READY != DongleBleState)
    {
        /*If device supports remote wake-up, maintain the connection in suspend mode*/
        if(isWakeupCapable)
        {
            /*Inform the Device for suspend mode, if it is connected*/
            if(!isPeripheralSuspended)
            {
                /*Write the HID Control point to suspend state*/
                if(CYBLE_ERROR_OK == Set_Device_ControlPoint(CYBLE_HIDS_CP_SUSPEND,0))
                {
                    isPeripheralSuspended = true;
                }
            }
        }
        else
        {
            /*Disconnect the device on suspend, if it doesnt support remote-wakeup*/
            BLE_Disconnect();
        }
    }
    else
    {
        /*Set this flag, so that on wake-up peripheral will be set to wake-up*/
        isPeripheralSuspended = true;
    }

    /*Switch OFF the LED, should be off when suspend occurs*/
    Led_Stop();

    pwrState = CyBle_EnterLPM(CYBLE_BLESS_DEEPSLEEP);

    /*Enter into deep sleep mode, as per BLE component state*/
    if(pwrState == CYBLE_BLESS_DEEPSLEEP)
    {
        CyGlobalIntDisable;
        blessState = CyBle_GetBleSsState();
        if(blessState == CYBLE_BLESS_STATE_ECO_ON || blessState == CYBLE_BLESS_STATE_DEEPSLEEP)
        {
            /*Send complete system components to deep sleep*/
            UART_Sleep();
            Timer_10ms_Stop(); 
            Timer_Stop();
            Led_Stop();
            isr_10ms_Stop();
            /*Send the CPU to sleep*/
            CySysPmDeepSleep();

            /*Restart the components after wakeup*/
            isr_10ms_StartEx(Transport_Timer_ISR);
            Timer_10ms_Start();
            Timer_Init(Device_Timer_Callback);
            UART_Wakeup();
        }
        CyGlobalIntEnable;
    }

    CyBle_ProcessEvents();

    /*Inform the Device to exit suspend mode, if it is connected*/
    if(DONGLE_BLE_STATE_NOT_READY != DongleBleState)
    {
        if(!isPeripheralSuspended)
        {
            if (CYBLE_ERROR_OK == Set_Device_ControlPoint(CYBLE_HIDS_CP_EXIT_SUSPEND, 0))
            {
                isPeripheralSuspended = false;
            }
        }
    }
}

/*****************************************************************************
* Function Name: BLE_Init()
******************************************************************************
* Summary:
* Starts BLE components and register callback functions for events.
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* None
*
*****************************************************************************/
void BLE_Init(void)
{
    #ifdef CYBLE_HIDS_CLIENT
    CyBle_HidsRegisterAttrCallback(HidsCallBack);
    #endif

    #ifdef CYBLE_BAS_CLIENT
    CyBle_BasRegisterAttrCallback(BasCallBack);
    #endif

    #ifdef CYBLE_SCPS_CLIENT
    CyBle_ScpsRegisterAttrCallback(ScpsCallBack);
    #endif

#ifdef ENABLE_PATH_LOSS_ALERT
    #ifdef CYBLE_TPS_CLIENT
    CyBle_TpsRegisterAttrCallback(TpsCallBack);
    #endif
#endif //ENABLE_PATH_LOSS_ALERT

    #ifdef CYBLE_LLS_CLIENT
    CyBle_LlsRegisterAttrCallback(LlsCallBack);
    #endif

    /*Re-init all the HID mode variables while entering HID Mode*/
    hidDeviceFound = false;
    skipProfileConfig = false;
    terminateLink = false;

    /*Set all the parameters to default, on HID mode*/
    /*scan in observation procedure, to get directed adv packets also*/
    cyBle_discoveryInfo.discProcedure = CYBLE_GAPC_OBSER_PROCEDURE;
    cyBle_discoveryInfo.scanType = CYBLE_GAPC_ACTIVE_SCANNING;
    cyBle_discoveryInfo.scanIntv = CYBLE_FAST_SCAN_INTERVAL;
    cyBle_discoveryInfo.scanWindow = CYBLE_FAST_SCAN_WINDOW;
    cyBle_discoveryInfo.ownAddrType = CYBLE_GAP_ADDR_TYPE_PUBLIC;
    cyBle_discoveryInfo.scanFilterPolicy = CYBLE_GAPC_ADV_ACCEPT_ALL_PKT;
    cyBle_discoveryInfo.scanTo = CYBLE_FAST_SCAN_TIMEOUT;
    cyBle_discoveryInfo.filterDuplicates = CYBLE_GAPC_FILTER_DUP_ENABLE;

    cyBle_connectionParameters.scanIntv = cyBle_discoveryInfo.scanIntv;
    cyBle_connectionParameters.scanWindow = cyBle_discoveryInfo.scanWindow;
    cyBle_connectionParameters.ownAddrType = cyBle_discoveryInfo.ownAddrType;
    cyBle_connectionParameters.initiatorFilterPolicy = cyBle_discoveryInfo.scanFilterPolicy;
    cyBle_connectionParameters.connIntvMin = CYBLE_GAPC_CONNECTION_INTERVAL_MIN;
    cyBle_connectionParameters.connIntvMax = CYBLE_GAPC_CONNECTION_INTERVAL_MAX;
    cyBle_connectionParameters.connLatency = CYBLE_GAPC_CONNECTION_SLAVE_LATENCY;
    cyBle_connectionParameters.supervisionTO = CYBLE_GAPC_CONNECTION_TIME_OUT;
    cyBle_connectionParameters.minCeLength = 0x0000u;
    cyBle_connectionParameters.maxCeLength = 0xFFFFu;

    cyBle_authInfo.security = CYBLE_GAP_SEC_MODE_1 | CYBLE_GAP_SEC_LEVEL_2;
    cyBle_authInfo.bonding = CYBLE_GAP_BONDING;
    cyBle_authInfo.ekeySize = 0x10u;
    cyBle_authInfo.authErr = CYBLE_GAP_AUTH_ERROR_NONE;

#ifdef ENABLE_PATH_LOSS_ALERT
    /*Reset the recorded RSSI samples on disconnection*/
    memset(rssiSamples, -(RSSI_THRESHOLD_VALUE), sizeof(rssiSamples));
#endif //ENABLE_PATH_LOSS_ALERT

    /*Disable automatic authentication procedures by component*/
    cyBle_eventHandlerFlag |= CYBLE_DISABLE_AUTOMATIC_AUTH;

    DongleBleState = DONGLE_BLE_STATE_NOT_READY;

    /* Start BLE component */
    if(CYBLE_ERROR_OK != CyBle_Start(BleCallBack))
    {
        DongleBleAssert();
    }
}

/*****************************************************************************
* Function Name: BLE_DeInit()
******************************************************************************
* Summary:
* This functions stops the BLE component and sets call back functions to NULL.
* This is called just before switching to CySmart tool.
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
* 
* Side Effects:
* None
* 
*****************************************************************************/
void BLE_DeInit(void)
{
    CyBle_Stop();

    #ifdef CYBLE_HIDS_CLIENT
        CyBle_HidsRegisterAttrCallback(NULL);
    #endif

    #ifdef CYBLE_BAS_CLIENT
        CyBle_BasRegisterAttrCallback(NULL);
    #endif

    #ifdef CYBLE_SCPS_CLIENT
        CyBle_ScpsRegisterAttrCallback(NULL);
    #endif

#ifdef ENABLE_PATH_LOSS_ALERT
    #ifdef CYBLE_TPS_CLIENT
        CyBle_TpsRegisterAttrCallback(NULL);
    #endif
#endif //ENABLE_PATH_LOSS_ALERT

    #ifdef CYBLE_LLS_CLIENT
        CyBle_LlsRegisterAttrCallback(NULL);
    #endif
}

/*******************************************************************************
* Function Name: Button_ISR
********************************************************************************
*
* Summary:
* ISR Callback function for user button pin, on interrupt this ISR will set button triggered flag
*
* Parameters:
* None
*
* Return:
* None
*
* Theory:
* None
*
* Side Effects:
* Modifies isButtonTriggered flag
*
*******************************************************************************/
CY_ISR(Button_ISR)
{
    isButtonTriggered = true;
    Pin_UserButton_ClearInterrupt();
}

/* [] END OF FILE */
